/**
 * 腾讯地图API服务工具类
 * 提供地图相关的API调用功能
 */

class TencentMapService {
	constructor() {
		this.apiKey = 'XA5BZ-3JIKJ-LHXFX-XAHBN-M7HWV-64BMN';
		this.baseUrl = 'https://apis.map.qq.com';
	}

	/**
	 * 路线规划API
	 * @param {Object} params 参数对象
	 * @param {Object} params.from 起点坐标 {lat: number, lng: number}
	 * @param {Object} params.to 终点坐标 {lat: number, lng: number}
	 * @param {String} params.mode 出行方式 driving(驾车) walking(步行) bicycling(骑行) transit(公交)
	 * @param {String} params.policy 路线策略 least_time(最快) least_distance(最短) avoid_highways(避开高速)
	 * @returns {Promise} 返回路线规划结果
	 */
	async getRoute(params) {
		try {
			const { from, to, mode = 'driving', policy = 'least_time' } = params;
			
			if (!from || !to) {
				throw new Error('起点和终点坐标不能为空');
			}

			const url = `${this.baseUrl}/ws/direction/v1/${mode}/`;
			const queryParams = {
				from: `${from.lat},${from.lng}`,
				to: `${to.lat},${to.lng}`,
				key: this.apiKey,
				policy: policy
			};

			const response = await this.request(url, queryParams);
			
			if (response.status === 0) {
				return this.formatRouteResponse(response);
			} else {
				throw new Error(`路线规划失败: ${response.message || '未知错误'}`);
			}
		} catch (error) {
			console.error('路线规划API调用失败:', error);
			throw error;
		}
	}

	/**
	 * 逆地理编码API
	 * @param {Object} location 坐标 {lat: number, lng: number}
	 * @returns {Promise} 返回地址信息
	 */
	async getAddress(location) {
		try {
			const { lat, lng } = location;
			
			if (!lat || !lng) {
				throw new Error('坐标不能为空');
			}

			const url = `${this.baseUrl}/ws/geocoder/v1/`;
			const queryParams = {
				location: `${lat},${lng}`,
				key: this.apiKey,
				get_poi: 1
			};

			const response = await this.request(url, queryParams);
			
			if (response.status === 0) {
				return this.formatAddressResponse(response);
			} else {
				throw new Error(`逆地理编码失败: ${response.message || '未知错误'}`);
			}
		} catch (error) {
			console.error('逆地理编码API调用失败:', error);
			throw error;
		}
	}

	/**
	 * 地理编码API
	 * @param {String} address 地址
	 * @returns {Promise} 返回坐标信息
	 */
	async getLocation(address) {
		try {
			if (!address) {
				throw new Error('地址不能为空');
			}

			const url = `${this.baseUrl}/ws/geocoder/v1/`;
			const queryParams = {
				address: address,
				key: this.apiKey
			};

			const response = await this.request(url, queryParams);
			
			if (response.status === 0) {
				return this.formatLocationResponse(response);
			} else {
				throw new Error(`地理编码失败: ${response.message || '未知错误'}`);
			}
		} catch (error) {
			console.error('地理编码API调用失败:', error);
			throw error;
		}
	}

	/**
	 * 搜索周边POI
	 * @param {Object} params 参数对象
	 * @param {Object} params.location 中心点坐标 {lat: number, lng: number}
	 * @param {String} params.keyword 搜索关键词
	 * @param {Number} params.radius 搜索半径(米)
	 * @param {Number} params.page_size 每页数量
	 * @param {Number} params.page_index 页码
	 * @returns {Promise} 返回POI搜索结果
	 */
	async searchNearby(params) {
		try {
			const { location, keyword, radius = 1000, page_size = 20, page_index = 1 } = params;
			
			if (!location || !keyword) {
				throw new Error('中心点坐标和搜索关键词不能为空');
			}

			const url = `${this.baseUrl}/ws/place/v1/search`;
			const queryParams = {
				boundary: `nearby(${location.lat},${location.lng},${radius})`,
				keyword: keyword,
				page_size: page_size,
				page_index: page_index,
				orderby: '_distance',
				key: this.apiKey
			};

			const response = await this.request(url, queryParams);
			
			if (response.status === 0) {
				return this.formatSearchResponse(response);
			} else {
				throw new Error(`POI搜索失败: ${response.message || '未知错误'}`);
			}
		} catch (error) {
			console.error('POI搜索API调用失败:', error);
			throw error;
		}
	}

	/**
	 * 计算两点间距离
	 * @param {Object} from 起点坐标 {lat: number, lng: number}
	 * @param {Object} to 终点坐标 {lat: number, lng: number}
	 * @returns {Promise} 返回距离信息
	 */
	async getDistance(from, to) {
		try {
			const { lat: lat1, lng: lng1 } = from;
			const { lat: lat2, lng: lng2 } = to;
			
			if (!lat1 || !lng1 || !lat2 || !lng2) {
				throw new Error('坐标不能为空');
			}

			const url = `${this.baseUrl}/ws/distance/v1/matrix`;
			const queryParams = {
				mode: 'driving',
				from: `${lat1},${lng1}`,
				to: `${lat2},${lng2}`,
				key: this.apiKey
			};

			const response = await this.request(url, queryParams);
			
			if (response.status === 0) {
				return this.formatDistanceResponse(response);
			} else {
				throw new Error(`距离计算失败: ${response.message || '未知错误'}`);
			}
		} catch (error) {
			console.error('距离计算API调用失败:', error);
			throw error;
		}
	}

	/**
	 * 发送HTTP请求
	 * @param {String} url 请求URL
	 * @param {Object} params 请求参数
	 * @returns {Promise} 返回响应数据
	 */
	request(url, params) {
		return new Promise((resolve, reject) => {
			// 构建查询字符串
			const queryString = Object.keys(params)
				.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
				.join('&');
			
			const fullUrl = `${url}?${queryString}`;
			
			uni.request({
				url: fullUrl,
				method: 'GET',
				timeout: 10000,
				success: (res) => {
					if (res.statusCode === 200) {
						resolve(res.data);
					} else {
						reject(new Error(`HTTP请求失败: ${res.statusCode}`));
					}
				},
				fail: (err) => {
					reject(new Error(`网络请求失败: ${err.errMsg || '未知错误'}`));
				}
			});
		});
	}

	/**
	 * 格式化路线规划响应
	 * @param {Object} response API响应
	 * @returns {Object} 格式化后的路线信息
	 */
	formatRouteResponse(response) {
		const result = response.result;
		if (!result || !result.routes || result.routes.length === 0) {
			throw new Error('未找到可行路线');
		}

		const route = result.routes[0];
		const steps = route.steps || [];
		
		return {
			distance: this.formatDistance(route.distance),
			duration: this.formatDuration(route.duration),
			polyline: route.polyline,
			steps: steps.map(step => ({
				instruction: step.instruction,
				distance: this.formatDistance(step.distance),
				duration: this.formatDuration(step.duration),
				polyline: step.polyline
			})),
			startLocation: {
				lat: result.routes[0].start_location.lat,
				lng: result.routes[0].start_location.lng
			},
			endLocation: {
				lat: result.routes[0].end_location.lat,
				lng: result.routes[0].end_location.lng
			}
		};
	}

	/**
	 * 格式化地址响应
	 * @param {Object} response API响应
	 * @returns {Object} 格式化后的地址信息
	 */
	formatAddressResponse(response) {
		const result = response.result;
		
		return {
			address: result.address,
			formatted_address: result.formatted_addresses?.recommend || result.address,
			location: {
				lat: result.location.lat,
				lng: result.location.lng
			},
			address_component: result.address_component,
			pois: result.pois || []
		};
	}

	/**
	 * 格式化坐标响应
	 * @param {Object} response API响应
	 * @returns {Object} 格式化后的坐标信息
	 */
	formatLocationResponse(response) {
		const result = response.result;
		
		return {
			location: {
				lat: result.location.lat,
				lng: result.location.lng
			},
			address: result.address,
			formatted_address: result.formatted_addresses?.recommend || result.address
		};
	}

	/**
	 * 格式化搜索响应
	 * @param {Object} response API响应
	 * @returns {Object} 格式化后的搜索结果
	 */
	formatSearchResponse(response) {
		const result = response.result;
		
		return {
			data: result.data || [],
			count: result.count || 0,
			total: result.total || 0
		};
	}

	/**
	 * 格式化距离响应
	 * @param {Object} response API响应
	 * @returns {Object} 格式化后的距离信息
	 */
	formatDistanceResponse(response) {
		const result = response.result;
		
		return {
			distance: this.formatDistance(result.elements[0].distance),
			duration: this.formatDuration(result.elements[0].duration)
		};
	}

	/**
	 * 格式化距离显示
	 * @param {Number} distance 距离(米)
	 * @returns {String} 格式化后的距离字符串
	 */
	formatDistance(distance) {
		if (distance < 1000) {
			return `${distance}m`;
		} else {
			return `${(distance / 1000).toFixed(1)}km`;
		}
	}

	/**
	 * 格式化时间显示
	 * @param {Number} duration 时间(秒)
	 * @returns {String} 格式化后的时间字符串
	 */
	formatDuration(duration) {
		const minutes = Math.floor(duration / 60);
		if (minutes < 60) {
			return `${minutes}分钟`;
		} else {
			const hours = Math.floor(minutes / 60);
			const remainingMinutes = minutes % 60;
			return remainingMinutes > 0 ? `${hours}小时${remainingMinutes}分钟` : `${hours}小时`;
		}
	}

	/**
	 * 解码polyline
	 * @param {String} encoded 编码的polyline字符串
	 * @returns {Array} 解码后的坐标点数组
	 */
	decodePolyline(encoded) {
		const points = [];
		let index = 0;
		const len = encoded.length;
		let lat = 0;
		let lng = 0;
		
		while (index < len) {
			let b, shift = 0, result = 0;
			do {
				b = encoded.charCodeAt(index++) - 63;
				result |= (b & 0x1f) << shift;
				shift += 5;
			} while (b >= 0x20);
			const dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
			lat += dlat;
			
			shift = 0;
			result = 0;
			do {
				b = encoded.charCodeAt(index++) - 63;
				result |= (b & 0x1f) << shift;
				shift += 5;
			} while (b >= 0x20);
			const dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
			lng += dlng;
			
			points.push({
				latitude: lat / 1e5,
				longitude: lng / 1e5
			});
		}
		
		return points;
	}

	/**
	 * 计算两点间直线距离
	 * @param {Object} from 起点坐标 {lat: number, lng: number}
	 * @param {Object} to 终点坐标 {lat: number, lng: number}
	 * @returns {Number} 距离(米)
	 */
	calculateStraightDistance(from, to) {
		const R = 6371000; // 地球半径（米）
		const dLat = (to.lat - from.lat) * Math.PI / 180;
		const dLng = (to.lng - from.lng) * Math.PI / 180;
		const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
			Math.cos(from.lat * Math.PI / 180) * Math.cos(to.lat * Math.PI / 180) *
			Math.sin(dLng/2) * Math.sin(dLng/2);
		const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
		return R * c;
	}
}

// 创建单例实例
const tencentMapService = new TencentMapService();

export default tencentMapService;
